#ifndef VIEW_INFO_HPP
#define VIEW_INFO_HPP 1

#include <vector>

#include "ViewChangeCertificate.hpp"
#include "Certificate.hpp"
#include "CheckPointState.hpp"

#include "../messages/ViewChange.hpp"
#include "../messages/ViewChangeAck.hpp"
#include "../messages/NewView.hpp"
#include "../messages/ConfirmView.hpp"

#include "../messages/CertificateEntry.hpp"
#include "../messages/Quorum.hpp"

namespace BFT
{
	namespace order
	{
		namespace statemanagement
		{
			class ViewInfo
			{
				public:
				
				ViewInfo(uint32_t _view, std::vector<boost::shared_ptr<ViewChangeCertificate> > _vcerts, bool _prim);
				
				void setMyViewChange(boost::shared_ptr<BFT::order::messages::ViewChange> _vc); //inlined
				
				boost::shared_ptr<BFT::order::messages::ViewChange> getMyViewChange(); //inlined
				
				void observeViewChange(boost::shared_ptr<BFT::order::messages::ViewChange> _vc);
				
				boost::shared_ptr<BFT::order::messages::ViewChange> getViewChange(uint32_t _replica); //inlined
				
				void addViewChangeAck(boost::shared_ptr<BFT::order::messages::ViewChangeAck> _vca);
				
				void addNewView(boost::shared_ptr<BFT::order::messages::NewView> _nv);
				
				boost::shared_ptr<BFT::order::messages::NewView> getNewViewMessage(); //inline
				
				void addConfirmation(boost::shared_ptr<BFT::order::messages::ConfirmView> _cv);
				
				void flushConfirmedCache();
				
				bool isConfirmed(); //inlined
				
				bool confirmedBy(int _i); //inlined
				
				boost::shared_ptr<BFT::order::messages::NewView> generateNewViewMessage(
					boost::shared_ptr<BFT::BaseNode> _bn);
				
				bool definedView(); //inlined
				
				std::vector<bool> getMissingViewChanges(); //inlined
				
				std::vector<uint32_t> getMissingCPs();
				
				void addCheckPointState(boost::shared_ptr<CheckPointState> _cps);
				
				bool addMyCP(boost::shared_ptr<CheckPointState> _cps);
				
				std::vector<bool> getMissingRequests();
				
				bool addEntry(boost::shared_ptr<BFT::messages::CertificateEntry> _entry, uint32_t _seqno);
				
				bool setCertificate(boost::shared_ptr<statemanagement::Certificate> _entry, uint32_t _seqno);
				
				boost::shared_ptr<BFT::messages::CertificateEntry> getEntry(uint32_t _seqno);
				
				std::vector<boost::shared_ptr<Certificate> > getEntries(int _i); //inlined
				
				bool isComplete();
				
				uint32_t getBaseSequenceNumber(); //inlined
				
				boost::shared_ptr<CheckPointState> getCommittedCP(); //inlined

				boost::shared_ptr<BFT::messages::Digest> getCommittedCPDigest(); //inlined
				
				boost::shared_ptr<CheckPointState> getStableCP(); //inlined

				boost::shared_ptr<BFT::messages::Digest> getStableCPDigest(); //inlined
				
				boost::shared_ptr<BFT::messages::HistoryDigest> getStableHistory(); //inlined
				
				boost::shared_ptr<CheckPointState> getWorkingState();
				
				uint32_t getNextSeqNo(); //inlined
				
				boost::shared_ptr<BFT::messages::HistoryDigest> getLastHistory();
				
				protected:
				
				int in1(int _i);
				
				int in2(int _i);
				
				//TODO need this stuff to stop cheating on view changes
				void defineView(bool _notPrimary);
				void defineView(char*, char*, bool); //TODO stop cheating!!! there shoud be treroot instead of char!
				void clearTrees();
//				protected void defineView(TreeRoot root, TreeRoot subroot, 
//			      		boolean notPrimary)
//			      	

			      	void populateVCTrees(boost::shared_ptr<BFT::order::messages::ViewChange> _vc);
				
				std::vector<std::vector<boost::shared_ptr<BFT::order::messages::ViewChangeAck> > > pendingAcks;
				std::vector<boost::shared_ptr<ViewChangeCertificate> > viewChanges;
				boost::shared_ptr<BFT::order::messages::NewView> newViewMsg;
				
				//TODO is a shared_ptr necessary here?
				boost::shared_ptr<BFT::messages::Quorum<BFT::order::messages::ConfirmView> > viewConfirmations; 
				
				std::vector<boost::shared_ptr<BFT::order::messages::ConfirmView> > cvCache;
				boost::shared_ptr<BFT::order::messages::ViewChange> myViewChange;
				
				std::vector<std::vector<boost::shared_ptr<Certificate> > > certs;
				std::vector<std::vector<boost::shared_ptr<BFT::messages::Digest> > > certDigests;				
				std::vector<std::vector<boost::shared_ptr<BFT::messages::HistoryDigest> > > histories;
				boost::shared_ptr<CheckPointState> committedCP;
				boost::shared_ptr<CheckPointState> stableCP;
				boost::shared_ptr<CheckPointState> workingState;
				boost::shared_ptr<BFT::messages::Digest> committedCPDigest;
				boost::shared_ptr<BFT::messages::Digest> stableCPDigest;

				uint32_t viewNo;
				uint32_t CPSeqNo; //seqno of the first request postcheckpoint
				uint32_t nextSeqNo; //the next seqno to be ordered
				
				bool primary;
				bool isCommitted;
				bool viewDefined; //to be initialized at false
				
				std::vector<bool> missingViews;
						
				//TODO stop cheating on view chages...
				//protected Vector<TreeRoot> trees;				
				
				
			};

			inline void ViewInfo::setMyViewChange(boost::shared_ptr<BFT::order::messages::ViewChange> _vc) 
				{myViewChange = _vc;}
				
			inline boost::shared_ptr<BFT::order::messages::ViewChange> ViewInfo::getMyViewChange() 
				{return myViewChange;}
			
			inline boost::shared_ptr<BFT::order::messages::ViewChange> ViewInfo::getViewChange(uint32_t _replica)
				{return viewChanges.at(_replica).get()->getViewChange();}

			inline boost::shared_ptr<BFT::order::messages::NewView> ViewInfo::getNewViewMessage() 
				{return newViewMsg;}
			
			inline bool ViewInfo::isConfirmed() 
				{return newViewMsg.use_count() != 0 && viewConfirmations.get()->isComplete();}
			
			inline bool ViewInfo::confirmedBy(int _i) {return viewConfirmations.get()->containsEntry(_i);}
			
			inline bool ViewInfo::definedView() {return viewDefined;}
			
			inline std::vector<bool> ViewInfo::getMissingViewChanges() {return missingViews;}
			
			inline std::vector<boost::shared_ptr<Certificate> > ViewInfo::getEntries(int _i)
				{return certs.at(_i);}
				
			inline uint32_t ViewInfo::getBaseSequenceNumber() {return CPSeqNo;}				
			
			inline boost::shared_ptr<CheckPointState> ViewInfo::getCommittedCP() {return committedCP;}
			
			inline boost::shared_ptr<BFT::messages::Digest> ViewInfo::getCommittedCPDigest()
				{return committedCPDigest;}
			
			inline boost::shared_ptr<CheckPointState> ViewInfo::getStableCP() {return stableCP;}
			
			inline boost::shared_ptr<BFT::messages::Digest> ViewInfo::getStableCPDigest()
				{return stableCPDigest;}
			
			inline boost::shared_ptr<BFT::messages::HistoryDigest> ViewInfo::getStableHistory()
				{return histories.at(0).at( histories.at(0).size() - 1 );}

			inline uint32_t ViewInfo::getNextSeqNo() {return nextSeqNo;}
			
			

		}
	}
}

#endif
